/**
 * testKMeans.h
 * 10/3/2009,CGCAD_THSS_THU_BJ
 * ubuntu8.04,g++4.2.4
 * Athour: Xinlai,Lu
 */

#include "testKMM.h"

vector<Point> *compute(string filename,
											 double &xmin, double &xmax, double &ymin, double &ymax, double &zmin, double &zmax,
											 double &scale,
  										 unsigned int &k, unsigned int &itrt
											);
int main(int argc, char *argv[])
{
  double xn, xx, yn, yx, zn, zx, sc;
  unsigned int itrt, k;
	vector<Point> *clusterCenters = compute(argv[1],
	        							 						      xn, xx, yn, yx, zn, zx,
				 								 					 				sc,
				 								 					 				k,
																					itrt);
  QApplication app(argc, argv);

	c[0] = (xx + xn)/2;
	c[1] = (yx + yn)/2;
	c[2] = (zx + zn)/2;

	glW *glw1 = new glW();
	glw1->set(xn, xx, yn, yx, zn, zx, sc, k, itrt, clusterCenters);
	glw1->setDisplayType(original);

	glW *glw2 = new glW();
	glw2->set(xn, xx, yn, yx, zn, zx, sc, k, itrt, clusterCenters);
	glw2->setDisplayType(initial);

	glW *glw3 = new glW();
	glw3->set(xn, xx, yn, yx, zn, zx, sc, k, itrt, clusterCenters);
	glw3->setDisplayType(ultimate);

	glW *glw4 = new glW();
	glw4->set(xn, xx, yn, yx, zn, zx, sc, k, itrt, clusterCenters);
	glw4->setDisplayType(current);

	if(argc < 2)
	{
		cerr << "Input a data file please..." << endl;
		return 0;
	}
  win window(glw1, glw2, glw3, glw4);
	window.setMaxItem(itrt, k);
	window.generateWindow();
	window.show();
  app.exec();

	delete []streamlines;
	delete []classHaveObj;
	delete []clusterCenters;

	return 0;
}

vector<Point> *compute(string filename,
											 double &xmin, double &xmax, double &ymin, double &ymax, double &zmin, double &zmax,
											 double &scale,
  										 unsigned int &k,
  										 unsigned int &itrt
											)
{
	Model t;
	UCDInputFile file(filename);
	file.FGetModel(t);	
	t.buildKDTree();
	t.getBound(xmin, xmax, ymin, ymax, zmin, zmax);
	cout << "Input the scale for display..." << endl;
	cin >> scale;

//	visKMeans km(&t);
	visKMedoids km(&t);
	cout << "input the number of streamlines: " << endl;
	int n;
	cin >> n;
	km.setSeedSources(n);
	double step, maxTime;
	cout << "Input the integration step length..." << endl;
	cin >> step;
	cout << "Input the integration maxLen..." << endl;
	cin >> maxTime;
	km.setParameters(step, maxTime);
	km.computeStreamlines();
	km.setSegment(20);
	km.computeLength();

	cout << "input the number of clusters for the K-Means:" << endl;
	cin >> k;
	cout << "input the most reiterations you accept:"<< endl;
	cin >> itrt;
	km.initClusters(k, itrt);
	unsigned int reit = 0;
	cout << "Clustering now, please wait..." << endl;
	do
	{
		/* Acoording to some similarity criterion, Choose the most recent center for each
		 * object(streamline).
		 */
//		cout << "reit	: " << reit << endl;
		km.relocate(reit);
		km.updateClusterCenters(reit);
	}while(/*_CLUSTERING_END != km.updateClusterCenters(reit) &&*/ ++reit < itrt);

	classHaveObj = km.getClsHaveObj();
	linesNum = km.getStreamlinesNumber();
	streamlines = new vector<Point>[linesNum];
	for(unsigned int i = 0; i < linesNum; i++)
	{
		for(unsigned int j = 0; j < km.getStreamlineSize(i); j++)
		{
			streamlines[i].push_back(km.getPointOnStreamline(i, j));
		}
	}

	km.releaseObjIsClass();
	return km.getClusterCenters();
}

GLuint glW::makeObject()
{
	GLuint list = glGenLists(1);
	glNewList(list, GL_COMPILE);

	glBegin(GL_LINES);
	drawFramework(xmin-c[0], xmax-c[0], ymin-c[1], ymax-c[1], zmin-c[2], zmax-c[2], scale);
	glEnd();

	switch(getDisplayType())
	{
		case original:
			{
				glColor3f((GLfloat)1, (GLfloat)0.1, (GLfloat)0.1);
				for(unsigned int i = 0; i < linesNum; i++)
				{
				  glBegin(GL_LINE_STRIP);
					for(unsigned int j = 0; j < streamlines[i].size(); j++)
					{
						Point tmp = streamlines[i][j];
						glVertex3f( (tmp.getX()-c[0])/scale, (tmp.getY()-c[1])/scale, (tmp.getZ()-c[2])/scale); 
					}
					glEnd();
				}
				break;
			}
		case initial:
			{
				glColor3f((GLfloat)1, (GLfloat)0.1, (GLfloat)0.1);
				for(unsigned int i = 0; i < k; i++)
				{
				  glBegin(GL_LINE_STRIP);
					for(unsigned int j = 0; j < streamlines[i].size(); j++)
					{
						Point tmp = streamlines[i][j];
						glVertex3f( (tmp.getX()-c[0])/scale, (tmp.getY()-c[1])/scale, (tmp.getZ()-c[2])/scale); 
					}
					glEnd();
				}
				glColor3f((GLfloat)0.1, (GLfloat)1, (GLfloat)0.1);
				for(unsigned int i = 0; i < k; i++)
				{
				  glBegin(GL_LINE_STRIP);
					for(unsigned int j = 0; j < clusterCenters[i].size(); j++)
					{
						Point tmp = clusterCenters[i][j];
						glVertex3f( (tmp.getX()-c[0])/scale, (tmp.getY()-c[1])/scale, (tmp.getZ()-c[2])/scale); 
					}
					glEnd();
				}
				break;
			}
		case ultimate:
			{
				glColor3f((GLfloat)1., (GLfloat)1., (GLfloat)0.1);
				for(unsigned int i = 0; i < k; i++)
				{
				  glBegin(GL_LINE_STRIP);
					for(unsigned int j = 0; j < clusterCenters[i+itrt*k].size(); j++)
					{
						Point tmp = clusterCenters[i+itrt*k][j];
						glVertex3f( (tmp.getX()-c[0])/scale, (tmp.getY()-c[1])/scale, (tmp.getZ()-c[2])/scale); 
					}
					glEnd();
				}
				break;
			}
		case current:
			{
				// itrtToDisplay, clsToDisplay
				glColor3f((GLfloat)0.1, (GLfloat)1, (GLfloat)1);
				glBegin(GL_LINE_STRIP);
				for(unsigned int j = 0; j < clusterCenters[clsToDisplay+itrtToDisplay*k].size(); j++)
				{
					Point tmp = clusterCenters[clsToDisplay+itrtToDisplay*k][j];
					glVertex3f( (tmp.getX()-c[0])/scale, (tmp.getY()-c[1])/scale, (tmp.getZ()-c[2])/scale); 
				}
				glEnd();

				glColor3f(1, 1, 0);
				for(unsigned int j = 0; j < classHaveObj[clsToDisplay+itrtToDisplay*k].size(); j++)
				{
					glBegin(GL_LINE_STRIP);
					unsigned int lineIndex = classHaveObj[clsToDisplay+itrtToDisplay*k][j];
					for(unsigned int m = 0; m < streamlines[lineIndex].size(); m++)
					{
						Point tmp = streamlines[lineIndex][m];
						glVertex3f( (tmp.getX()-c[0])/scale, (tmp.getY()-c[1])/scale, (tmp.getZ()-c[2])/scale); 
					}
					glEnd();
				}
				break;
			}
		default:
			{
				cout << "Error, unkown or incorrect display type at line " << __LINE__ << " of file " << __FILE__ << endl;
				exit(-1);
			}
	}
	glEndList();
	return list;
}
